/*
 * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
 *
 * https://www.mall4j.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */
package com.yami.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.model.Product;
import com.yami.shop.bean.model.Sku;
import com.yami.shop.bean.model.Supplier;
import com.yami.shop.bean.model.SupplierProd;
import com.yami.shop.bean.vo.SupplierProdVO;
import com.yami.shop.bean.vo.SupplierSkuVO;
import com.yami.shop.common.config.Constant;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.util.PageAdapter;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.PoiExcelUtil;
import com.yami.shop.dao.ProductMapper;
import com.yami.shop.dao.SupplierProdMapper;
import com.yami.shop.service.SkuService;
import com.yami.shop.service.SupplierProdService;
import com.yami.shop.service.SupplierService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Citrus
 * @date 2021-09-07 10:12:32
 */
@Service
public class SupplierProdServiceImpl extends ServiceImpl<SupplierProdMapper, SupplierProd> implements SupplierProdService {

    @Autowired
    private SupplierProdMapper supplierProdMapper;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private SkuService skuService;
    @Autowired
    private SupplierService supplierService;

    @Override
    @Cacheable(cacheNames = "listSupplierProd", key = "#supplierId")
    public List<SupplierProdVO> listSupplierProd(Long supplierId) {
        return supplierProdMapper.listSupplierProd(supplierId, I18nMessage.getDbLang());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addOrUpdate(List<SupplierProd> supplierProds, Long supplierId) {
        List<SupplierProd> dbSupplierProdList = list(new LambdaQueryWrapper<SupplierProd>().eq(SupplierProd::getSupplierId, supplierId));
        List<SupplierProd> prodList = this.checkInfo(supplierProds, supplierId);
        List<Long> dbProdIds = dbSupplierProdList.stream().map(SupplierProd::getSupplierProdId).collect(Collectors.toList());
        if (CollUtil.isEmpty(prodList) && CollUtil.isNotEmpty(dbProdIds)) {
            return removeByIds(dbProdIds);
        } else if (CollUtil.isNotEmpty(dbProdIds)) {
            List<Long> deleteIds = new ArrayList<>();
            for (SupplierProd supplierProd : prodList) {
                if (Objects.nonNull(supplierProd.getSupplierProdId()) && dbProdIds.contains(supplierProd.getSupplierProdId())) {
                    deleteIds.add(supplierProd.getSupplierProdId());
                }
            }
            dbProdIds.removeAll(deleteIds);
            boolean updateBatch = saveOrUpdateBatch(prodList);
            if (CollUtil.isNotEmpty(dbProdIds)) {
                removeByIds(dbProdIds);
            }
            return updateBatch;
        } else if (CollUtil.isEmpty(dbProdIds) && CollUtil.isNotEmpty(prodList)) {
            return saveBatch(prodList);
        }
        return false;
    }

    @Override
    public void downLoadModel(HttpServletResponse response) {
        createExcel(null, response);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object parseFile(MultipartFile file, Long shopId, Long supplierId) throws Exception {
        try (InputStream inputStream = file.getInputStream();
             Workbook workbook = WorkbookFactory.create(inputStream)) {
            Sheet sheet = workbook.getSheetAt(0);
            int rowNumber = sheet.getPhysicalNumberOfRows();
            if (rowNumber <= Constant.EXCEL_BEGIN_ROW) {
                // 文件无内容
                throw new YamiShopBindException("yami.document.no.content");
            }
            if (!(file.getOriginalFilename().contains(Constant.XLS_FILE) || file.getOriginalFilename().contains(Constant.XLSX_FILE))) {
                // 格式错误
                throw new YamiShopBindException("yami.file.error");
            }
            //商品编码对应的skuId以及prodId
            List<Product> products = productMapper.selectList(new LambdaQueryWrapper<Product>().eq(Product::getShopId, shopId)
                    .ne(Product::getStatus, -1));
            List<Long> prodIds = products.stream().map(Product::getProdId).collect(Collectors.toList());
            List<String> partyCodes = skuService.listSkuByProdIds(prodIds, null);
            //已有的供应商商品编码/单品条码
            List<String> partyCodeList = supplierProdMapper.getPartyCodeList(supplierId);
            List<SupplierProd> supplierProds = new ArrayList<>();
            List<String> errorList = new ArrayList<>();
            String response;
            int insertRows = 0;
            for (int i = 2; i < rowNumber; i++) {
                try {
                    Row row = sheet.getRow(i);
                    int cell = 0;
                    //{"商品编码", "商品名称", "最小订货量", "采购价"}
                    String partyCode = PoiExcelUtil.getRowValue(row, cell, false);
                    String prodName = PoiExcelUtil.getRowValue(row, ++cell, false);
                    String minOrderQuantity = PoiExcelUtil.getRowValue(row, ++cell, true);
                    String price = PoiExcelUtil.getRowValue(row, ++cell, true);
                    insertRows++;
                    int minOrderCount = 1;
                    double purchasePrice = 0.01;
                    try {
                        if (Objects.nonNull(minOrderQuantity) && Integer.parseInt(minOrderQuantity) > 1) {
                            minOrderCount = Integer.parseInt(minOrderQuantity);
                        }
                        if (Objects.nonNull(price) && Double.parseDouble(price) > 0.01) {
                            purchasePrice = Double.parseDouble(price);
                        }
                    } catch (NumberFormatException e) {
                        throw new YamiShopBindException("输入内容[" + e.getMessage().substring(18) + "]格式错误");
                    }
                    List<Sku> skus;
                    if (StrUtil.isBlank(partyCode) || !partyCodes.contains(partyCode)) {
                        //商品编码不存在
                        throw new YamiShopBindException("yami.sku.party.code.not.exist");
                    }
                    skus = skuService.list(new LambdaQueryWrapper<Sku>().eq(Sku::getPartyCode, partyCode));
                    if (skus.size() > 1) {
                        //该商品编码下存在多个商品规格，请更新对应的商品规格编码后重新导入
                        throw new YamiShopBindException("yami.sku.party.code.is.repeated");
                    }
                    //去重
                    if (partyCodeList.contains(partyCode)) {
                        continue;
                    }
                    partyCodeList.add(partyCode);
                    SupplierProd supplierProd = getSupplierProd(supplierId, minOrderCount, purchasePrice, skus);
                    supplierProds.add(supplierProd);
                } catch (Exception e) {
                    errorList.add("第" + (i + 1) + "行数据有错误：" + e.getMessage());
                }
            }
            //供应商商品不为空批量导入
            if (CollectionUtils.isNotEmpty(supplierProds)) {
                addOrUpdate(supplierProds, supplierId);
                response = "检查到" + insertRows + "条供应商商品信息，成功导入" +
                        supplierProds.size() + "条供应商商品信息！错误" + errorList.size() + "条供应商商品信息！" +
                        (CollUtil.isNotEmpty(errorList) ? errorList.toString() : "");
                return response;
            }
            response = "检查到" + insertRows + "条有效供应商商品信息,导入0条";
            if (CollUtil.isNotEmpty(errorList)) {
                response = response + errorList.toString();
            }
            return response;
        } catch (Exception e) {
            return e.getMessage();
        }
    }

    @NotNull
    private SupplierProd getSupplierProd(Long supplierId, int minOrderCount, double purchasePrice, List<Sku> skus) {
        SupplierProd supplierProd = new SupplierProd();
        Sku sku = skus.get(0);
        supplierProd.setProdId(sku.getProdId());
        supplierProd.setSkuId(sku.getSkuId());
        supplierProd.setPurchasePrice(purchasePrice);
        supplierProd.setMinOrderQuantity(minOrderCount);
        supplierProd.setSupplierId(supplierId);
        return supplierProd;
    }

    @Override
    public void exportSupplierProd(Long supplierId, HttpServletResponse response) {
        List<SupplierProdVO> supplierProdList = supplierProdMapper.getByParam(supplierId, I18nMessage.getDbLang());
        createExcel(supplierProdList, response);
    }

    @Override
    public void deleteByProdId(Long prodId) {
        if (Objects.isNull(prodId)) {
            return;
        }
        supplierProdMapper.deleteByProdId(prodId);
    }

    @Override
    public List<Long> listSupplierIdByProdId(Long prodId) {
        return supplierProdMapper.listSupplierIdByProdId(prodId);
    }

    @Override
    public List<Long> listSupplierIdBySkuIds(List<Long> skuIds) {
        if (CollUtil.isEmpty(skuIds)) {
            return new ArrayList<>();
        }
        return supplierProdMapper.listSupplierIdBySkuIds(skuIds);
    }

    @Override
    public IPage<SupplierProdVO> supplierProdPage(PageParam<SupplierProdVO> pageParam, Supplier supplier, String partyCode) {
        List<SupplierProdVO> supplierProdList = supplierProdMapper.supplierProdList(new PageAdapter(pageParam), supplier.getSupplierId(), partyCode);
        pageParam.setRecords(supplierProdList);
        pageParam.setTotal(supplierProdMapper.supplierProdTotal(supplier.getSupplierId(), partyCode));
        if (CollUtil.isEmpty(supplierProdList)) {
            return pageParam;
        }
        loadSupplierProdInfo(supplierProdList);
        return pageParam;
    }

    private void loadSupplierProdInfo(List<SupplierProdVO> supplierProdList) {
        List<Long> prodIds = new ArrayList<>();
        List<Long> skuIds = new ArrayList<>();
        for (SupplierProdVO supplierProdVO : supplierProdList) {
            prodIds.add(supplierProdVO.getProdId());
            skuIds.addAll(supplierProdVO.getSkuList().stream().map(SupplierSkuVO::getSkuId).collect(Collectors.toList()));
        }
        // 普通商品信息
        Map<Long, Product> prodMap;
        if (CollUtil.isNotEmpty(prodIds) && CollUtil.isNotEmpty(skuIds)) {
            List<Product> products = productMapper.prodAndSkuInfo(prodIds, skuIds, I18nMessage.getLang());
            prodMap = products.stream().collect(Collectors.toMap(Product::getProdId, p -> p));
        } else {
            prodMap = new HashMap<>(0);
        }
        // 合并数据
        for (SupplierProdVO supplierProdVO : supplierProdList) {
            if (!prodMap.containsKey(supplierProdVO.getProdId())) {
                continue;
            }
            Product product = prodMap.get(supplierProdVO.getProdId());
            supplierProdVO.setProdName(product.getProdName());
            supplierProdVO.setPic(product.getPic());
            Map<Long, Sku> skuMap = product.getSkuList().stream().collect(Collectors.toMap(Sku::getSkuId, s -> s));
            for (SupplierSkuVO supplierSkuVO : supplierProdVO.getSkuList()) {
                Sku sku = skuMap.get(supplierSkuVO.getSkuId());
                if (Objects.isNull(sku)) {
                    continue;
                }
                supplierSkuVO.setPic(sku.getPic());
                supplierSkuVO.setStocks(sku.getStocks());
                supplierSkuVO.setSkuName(sku.getSkuName());
                supplierSkuVO.setPartyCode(sku.getPartyCode());
            }
        }
    }

    @Override
    @CacheEvict(cacheNames = "listSupplierProd", key = "#supplierId")
    public void removeCacheBySupplierId(Long supplierId) {
    }

    @Override
    public void deleteByProdId(Long prodId, List<Long> skuIds) {
        if (Objects.isNull(prodId) && CollUtil.isEmpty(skuIds)) {
            return;
        }
        //删除对应的商品
        supplierProdMapper.deleteBySkuIds(prodId, skuIds);
    }

    @Override
    public IPage<SupplierProdVO> defaultSupplierProdPage(PageParam<SupplierProdVO> pageParam, Supplier supplier, String partyCode) {
        List<SupplierProdVO> list = supplierProdMapper.defaultSupplierProdPage(new PageAdapter(pageParam), supplier, partyCode, I18nMessage.getLang());
        pageParam.setRecords(list);
        pageParam.setTotal(supplierProdMapper.defaultSupplierProdTotal(supplier, partyCode));
        if (CollUtil.isEmpty(list)) {
            return pageParam;
        }
        for (SupplierProdVO supplierProdVO : list) {
            for (SupplierSkuVO supplierSkuVO : supplierProdVO.getSkuList()) {
                supplierSkuVO.setMinOrderQuantity(1);
            }
        }
        return pageParam;
    }

    @Override
    public List<SupplierProdVO> listSupplierProdByPartyCodeList(List<String> partyCodeList) {
        List<SupplierProdVO> supplierProds = supplierProdMapper.listSupplierProdByPartyCodeList(partyCodeList, I18nMessage.getLang());
        return supplierProds;
    }

    private void createExcel(List<SupplierProdVO> supplierProdList, HttpServletResponse response) {
        ExcelWriter writer = ExcelUtil.getBigWriter();
        List<String> headerList;
        String[] headerCn = {"商品编码（必填*）", "商品名称", "最小订货量", "采购价"};
        String[] headerEn = {"Product Code(Require*)", "Product Name", "Minimum order quantity", "Purchase price"};
        headerList = Arrays.asList(Objects.equals(I18nMessage.getDbLang(), 0) ? headerCn : headerEn);
        Sheet sheet = writer.getSheet();
        int length = headerCn.length -1;
        for (int i = 0; i < length; i++) {
            sheet.setColumnWidth(i, 30 * 256);
        }
        writer.merge(headerList.size() - 1, Objects.equals(I18nMessage.getDbLang(), 0) ? "供应商商品模板信息" : "Supplier product template information");
        writer.writeRow(headerList);
        int row = 1;
        if (CollectionUtils.isNotEmpty(supplierProdList)) {
            for (SupplierProdVO supplierProd : supplierProdList) {
                int firstRow = ++row;
                int col = -1;
                //商品编码
                PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplierProd.getPartyCode());
                //商品名称
                PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplierProd.getProdName());
                //最小订货量
                PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplierProd.getMinOrderQuantity());
                //采购价
                PoiExcelUtil.mergeIfNeed(writer, firstRow, firstRow, ++col, col, supplierProd.getPurchasePrice());
            }
        }
        PoiExcelUtil.writeExcel(response, writer);
    }

    private List<SupplierProd> checkInfo(List<SupplierProd> supplierProds, Long supplierId) {
        Supplier supplier = supplierService.getById(supplierId);
        if (Objects.equals(supplier.getStatus(), 0)) {
            throw new YamiShopBindException("yami.supplier.status.error");
        }
        List<Long> skuIds = supplierProds.stream().map(SupplierProd::getSkuId).collect(Collectors.toList());
        List<Sku> skus = skuService.listSkuBySKuIds(skuIds);
        Map<Long, Sku> skuMap = skus.stream().collect(Collectors.toMap(Sku::getSkuId, s -> s));
        ArrayList<SupplierProd> addList = new ArrayList<>();
        for (SupplierProd prod : supplierProds) {
            Sku sku = skuMap.get(prod.getSkuId());
            if (Objects.isNull(sku) || sku.getIsDelete() == 1) {
                continue;
            }
            addList.add(prod);
        }
        return addList;
    }
}
